package com.xique.door.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import com.xique.common.core.enums.UserStatus;
import com.xique.common.core.utils.DateUtils;
import com.xique.common.core.utils.OrikaUtil;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.door.bean.domain.*;
import com.xique.door.bean.dto.UserBuildingInfoDTO;
import com.xique.door.bean.request.visitor.*;
import com.xique.door.bean.vo.visitor.VisitorAuthorizeListVO;
import com.xique.door.bean.vo.visitor.VisitorDetailVO;
import com.xique.door.bean.vo.visitor.VisitorListVO;
import com.xique.door.biz.service.IVisitorBizService;
import com.xique.door.command.IDeviceVisitorCommandService;
import com.xique.door.constant.DoorDeviceConstant;
import com.xique.door.constant.VisitorConstants;
import com.xique.door.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shd
 * @create 2022/2/26 10:32
 */
@Service
public class VisitorBizServiceImpl implements IVisitorBizService {

    @Autowired
    private IVisitorService visitorService;

    @Autowired
    private IVisitorDeviceService visitorDeviceService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IAccessDeviceService accessDeviceService;

    @Autowired
    private IBuildHouseService houseService;

    @Autowired
    private IDeviceVisitorCommandService deviceVisitorCommandService;

    @Autowired
    private IBuildingDeviceService buildingDeviceService;

    @Override
    public AjaxResult getVisitorList(VisitorListRequest request) {

        Map<String, Object> map = new HashMap<>(2);
        map.put("list", new ArrayList<>());
        map.put("total", 0);

        request.setParkId(SecurityUtils.getParkId());

        List<Visitor> list = visitorService.selectVisitorListV2(request);
        if (CollectionUtils.isEmpty(list)) {
            return AjaxResult.success(map);
        }
        Map<String, String> voMap = new HashMap<>(2);
        voMap.put("phone", "visitorPhone");
        voMap.put("createTime", "time");
        List<VisitorListVO> vos = OrikaUtil.converts(list, VisitorListVO.class, voMap);
        if (CollectionUtils.isEmpty(vos)) {
            return AjaxResult.success(new HashMap<>(0));
        }

        long total = new PageInfo(list).getTotal();
        map.put("list", vos);
        map.put("total", total);

        return AjaxResult.success(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AjaxResult addVisitor(VisitorAddRequest request) {

        User user = userService.selectUserById(request.getUserId());
        if (StringUtils.isNull(user)) {
            return AjaxResult.error("未找到被访人");
        }
        if (UserStatus.USER_DISABLE.getCode().equals(user.getStatus())) {
            return AjaxResult.error("被访人账号已停用");
        }

        Visitor visitor = OrikaUtil.convert(request, Visitor.class);
        visitor.setParkId(StringUtils.isNull(request.getParkId()) ? SecurityUtils.getParkId() : request.getParkId());
        visitor.setPhone(request.getVisitorPhone());
        visitor.setVerifyStatus(VisitorConstants.VerifyStatus.PASS);
        visitor.setVerifyType(request.getVerifyType());

        BuildHouseV1 house = houseService.getById(visitor.getHouseId());
        visitor.setHouseCode(house.getHouseCode());

        int count = visitorService.insertVisitor(visitor);
        if (count <= 0) {
            return AjaxResult.error("添加失败");
        }

        BuildingDevice search = new BuildingDevice();
        search.setBuildingId(request.getBuildingId());
        List<BuildingDevice> buildingDeviceList = buildingDeviceService.selectBuildingDeviceList(search);

        List<Long> deviceIds = buildingDeviceList.stream().map(BuildingDevice::getDeviceId).distinct().collect(Collectors.toList());
        List<AccessDevice> accessDeviceList = accessDeviceService.selectAccessDeviceByIds(deviceIds);
        Map<Long, AccessDevice> accessDeviceMap = accessDeviceList.stream().collect(Collectors.toMap(AccessDevice::getId, o -> o));

        if (CollectionUtils.isNotEmpty(buildingDeviceList)) {
            List<VisitorDevice> inserts = new ArrayList<>(buildingDeviceList.size());
            buildingDeviceList.forEach(item -> {
                VisitorDevice visitorDevice = new VisitorDevice();
                visitorDevice.setParkId(visitor.getParkId());
                visitorDevice.setVisitorId(visitor.getId());
                visitorDevice.setCustomId(visitor.getCustomId());
                visitorDevice.setDeviceId(item.getDeviceId());
                if (StringUtils.isEmpty(visitor.getFaceUrl())) {
                    visitorDevice.setStatus(DoorDeviceConstant.DeviceStatus.NOFACE);
                } else {
                    visitorDevice.setStatus(DoorDeviceConstant.DeviceStatus.SEND);
                }
                if (StringUtils.isNotNull(accessDeviceMap.get(item.getDeviceId()))) {
                    visitorDevice.setDevSn(accessDeviceMap.get(item.getDeviceId()).getDevSn());
                    visitorDevice.setModel(accessDeviceMap.get(item.getDeviceId()).getModel());
                }
                visitorDevice.setVisitorType(request.getVisitorType());
                visitorDevice.setStartTime(request.getStartTime());
                visitorDevice.setEndTime(request.getEndTime());
                visitorDevice.setEffectNumber(request.getEffectNumber());
                visitorDevice.setCreateTime(DateUtils.getNowDate());
                visitorDevice.setCreateUser(SecurityUtils.getUserId());
                visitorDevice.setUpdateTime(DateUtils.getNowDate());
                visitorDevice.setUpdateUser(SecurityUtils.getUserId());

                // 如果设备sn是空得话，就不传入集合中
                if(StringUtils.isNotEmpty(visitorDevice.getDevSn())){
                    inserts.add(visitorDevice);
                }

            });

            boolean isSuccess = visitorDeviceService.saveBatch(inserts);
            if (!isSuccess) {
                return AjaxResult.error("访客绑定设备失败");
            }

            if (StringUtils.isNotEmpty(visitor.getFaceUrl())) {
                // TODO 下发访客信息到设备
                deviceVisitorCommandService.downDevicesVisitors(accessDeviceList, Collections.singletonList(visitor));
            }
        }

        return AjaxResult.success("添加成功");
    }

    @Override
    public AjaxResult visitorDetail(Long id) {

        if (StringUtils.isNull(id)) {
            return AjaxResult.error("请传入访客id");
        }

        Visitor visitor = visitorService.selectVisitorById(id);
        UserBuildingInfoDTO dto = userService.selectUserBuildInfo(visitor.getUserId(), visitor.getHouseId(), visitor.getBuildingId(), visitor.getAreaId());

        VisitorDetailVO vo = OrikaUtil.convert(visitor, VisitorDetailVO.class, Collections.singletonMap("phone", "visitorPhone"));
        vo.setUserInfo(dto);

        return AjaxResult.success(vo);
    }

    @Override
    public AjaxResult editVisitor(VisitorEditRequest request) {

        Visitor visitor = visitorService.selectVisitorById(request.getId());
        if (StringUtils.isNull(visitor)) {
            return AjaxResult.error("未找到对应访客");
        }
        String oldFaceKey = visitor.getFaceKey();

        Visitor update = OrikaUtil.convert(request, Visitor.class);

        int count = visitorService.updateVisitor(update);
        if (count <= 0) {
            return AjaxResult.error("编辑失败");
        }

        if (StringUtils.isNotEmpty(request.getFaceKey()) && !request.getFaceKey().equals(oldFaceKey)) {
            QueryWrapper<VisitorDevice> condition = new QueryWrapper<>();
            condition.eq("visitor_id", visitor.getId());
            List<VisitorDevice> visitorDeviceList = visitorDeviceService.list(condition);
            if (CollectionUtils.isEmpty(visitorDeviceList)) {
                return AjaxResult.success("编辑成功");
            }
            visitor.setFaceUrl(request.getFaceUrl());
            visitor.setFaceKey(request.getFaceKey());

            List<Long> deviceIds = visitorDeviceList.stream().map(VisitorDevice::getDeviceId).distinct().collect(Collectors.toList());
            List<AccessDevice> accessDeviceList = accessDeviceService.selectAccessDeviceByIds(deviceIds);

            deviceVisitorCommandService.downDevicesVisitors(accessDeviceList, Collections.singletonList(visitor));
        }

        return AjaxResult.success("编辑成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AjaxResult removeVisitor(Long id) {
        if (StringUtils.isNull(id)) {
            return AjaxResult.error("访客id不能为空");
        }

        // TODO 下发删除访客信息到设备
        QueryWrapper<VisitorDevice> condition = new QueryWrapper<>();
        condition.eq("visitor_id", id);
        List<VisitorDevice> list = visitorDeviceService.list(condition);

        List<Long> deviceIds = list.stream().map(VisitorDevice::getDeviceId).collect(Collectors.toList());
        List<AccessDevice> accessDeviceList = accessDeviceService.selectAccessDeviceByIds(deviceIds);

        Visitor visitor = visitorService.selectVisitorById(id);

        deviceVisitorCommandService.deleteDevicesVisitors(accessDeviceList, Collections.singletonList(visitor));

        List<Long> visitorDeviceIds = list.stream().map(VisitorDevice::getId).collect(Collectors.toList());

        visitorDeviceService.removeByIds(visitorDeviceIds);

        int count = visitorService.deleteVisitorById(id);
        if (count <= 0) {
            return AjaxResult.error("删除失败");
        }

        return AjaxResult.success("删除成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AjaxResult changeVisitorStatus(VisitorEditRequest request) {

        if (StringUtils.isNull(request.getId())) {
            return AjaxResult.error("访客id不能为空");
        }
        if (StringUtils.isNull(request.getStatus())) {
            return AjaxResult.error("访客状态不能为空");
        }

        Visitor visitor = visitorService.selectVisitorById(request.getId());
        if (StringUtils.isNull(visitor)) {
            return AjaxResult.error("未找到对应访客");
        }

        if (StringUtils.isNotEmpty(visitor.getFaceKey())) {
            QueryWrapper<VisitorDevice> condition = new QueryWrapper<>();
            condition.eq("visitor_id", request.getId());
            List<VisitorDevice> list = visitorDeviceService.list(condition);

            if (CollectionUtils.isNotEmpty(list)) {
                List<Long> deviceIds = list.stream().map(VisitorDevice::getDeviceId).collect(Collectors.toList());
                List<AccessDevice> accessDeviceList = accessDeviceService.selectAccessDeviceByIds(deviceIds);

                if (VisitorConstants.Status.NORMAL == request.getStatus()) {
                    deviceVisitorCommandService.downDevicesVisitors(accessDeviceList, Collections.singletonList(visitor));
                }
                if (VisitorConstants.Status.PAUSE == request.getStatus()) {
                    deviceVisitorCommandService.deleteDevicesVisitors(accessDeviceList, Collections.singletonList(visitor));
                }
            }
        }

        Visitor update = new Visitor();
        update.setId(request.getId());
        update.setStatus(request.getStatus().toString());

        int count = visitorService.updateVisitor(update);
        if (count <= 0) {
            return AjaxResult.error("修改失败");
        }

        return AjaxResult.success("修改成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AjaxResult verifyVisitor(VisitorVerifyRequest request) {

        Visitor update = OrikaUtil.convert(request, Visitor.class);
        update.setVerifyType(VisitorConstants.VerifyType.ESTATE);

        int count = visitorService.updateVisitor(update);
        if (count <= 0) {
            return AjaxResult.error("审核失败");
        }

        if (VisitorConstants.VerifyStatus.PASS.equals(request.getVerifyStatus())) {

            Visitor visitor = visitorService.selectVisitorById(request.getId());

            BuildingDevice search = new BuildingDevice();
            search.setBuildingId(visitor.getBuildingId());
            List<BuildingDevice> buildingDeviceList = buildingDeviceService.selectBuildingDeviceList(search);

            List<Long> deviceIds = buildingDeviceList.stream().map(BuildingDevice::getDeviceId).distinct().collect(Collectors.toList());
            List<AccessDevice> accessDeviceList = accessDeviceService.selectAccessDeviceByIds(deviceIds);
            Map<Long, AccessDevice> accessDeviceMap = accessDeviceList.stream().collect(Collectors.toMap(AccessDevice::getId, o -> o));

            List<VisitorDevice> inserts = new ArrayList<>(buildingDeviceList.size());
            buildingDeviceList.forEach(item -> {
                VisitorDevice visitorDevice = new VisitorDevice();
                visitorDevice.setParkId(visitor.getParkId());
                visitorDevice.setVisitorId(visitor.getId());
                visitorDevice.setCustomId(visitor.getCustomId());
                visitorDevice.setDeviceId(item.getDeviceId());
                visitorDevice.setStatus(DoorDeviceConstant.DeviceStatus.SEND);
                if (StringUtils.isNotNull(accessDeviceMap.get(item.getDeviceId()))) {
                    visitorDevice.setDevSn(accessDeviceMap.get(item.getDeviceId()).getDevSn());
                    visitorDevice.setModel(accessDeviceMap.get(item.getDeviceId()).getModel());
                }
                visitorDevice.setVisitorType(visitor.getVisitorType());
                visitorDevice.setStartTime(visitor.getStartTime());
                visitorDevice.setEndTime(visitor.getEndTime());
                visitorDevice.setEffectNumber(visitor.getEffectNumber().intValue());
                visitorDevice.setCreateTime(DateUtils.getNowDate());
                visitorDevice.setCreateUser(SecurityUtils.getUserId());
                visitorDevice.setUpdateTime(DateUtils.getNowDate());
                visitorDevice.setUpdateUser(SecurityUtils.getUserId());

                inserts.add(visitorDevice);
            });

            boolean isSuccess = visitorDeviceService.saveBatch(inserts);
            if (!isSuccess) {
                return AjaxResult.error("访客绑定设备失败");
            }

            // TODO 下发访客信息到设备
            deviceVisitorCommandService.downDevicesVisitors(accessDeviceList, Collections.singletonList(visitor));
        }

        return AjaxResult.success("审核完成");
    }

    @Override
    public AjaxResult visitorAuthorizeList(VisitorAuthorizeListRequest request) {

        request.setParkId(SecurityUtils.getParkId());

        Map<String, Object> resultMap = new HashMap<>(2);
        resultMap.put("total", 0);
        resultMap.put("list", new ArrayList<>());

        List<VisitorDevice> list = visitorDeviceService.selectVisitorAuthorizeList(request);
        if (CollectionUtils.isEmpty(list)) {
            return AjaxResult.success(resultMap);
        }
        int total = visitorDeviceService.selectVisitorAuthorizeCount(request);

        List<Long> visitorIds = list.stream().map(VisitorDevice::getVisitorId).distinct().collect(Collectors.toList());
        List<Visitor> visitorList = visitorService.selectVisitorByIds(visitorIds);
        Map<Long, Visitor> visitorMap = visitorList.stream().collect(Collectors.toMap(Visitor::getId, item -> item));

        List<Long> deviceIds = list.stream().map(VisitorDevice::getDeviceId).distinct().collect(Collectors.toList());
        List<AccessDevice> deviceList = accessDeviceService.selectAccessDeviceWithBuildByIds(deviceIds);
        Map<Long, AccessDevice> deviceMap = deviceList.stream().collect(Collectors.toMap(AccessDevice::getId, item -> item));

        List<VisitorAuthorizeListVO> vos = new ArrayList<>(list.size());
        list.forEach(item -> {
            VisitorAuthorizeListVO vo = OrikaUtil.convert(item, VisitorAuthorizeListVO.class);
            if (StringUtils.isNotNull(visitorMap.get(item.getVisitorId()))) {
                Visitor visitor = visitorMap.get(item.getVisitorId());
                vo.setVisitorName(visitor.getVisitorName());
                vo.setVisitorPhone(visitor.getPhone());
                vo.setStartTime(visitor.getStartTime());
                vo.setEndTime(visitor.getEndTime());
            }
            if (StringUtils.isNotNull(deviceMap.get(item.getDeviceId()))) {
                AccessDevice device = deviceMap.get(item.getDeviceId());
                vo.setDeviceName(device.getName());
                vo.setBuildName(device.getBuildName());
            }
            vos.add(vo);
        });

        resultMap.put("list", vos);
        resultMap.put("total", total);

        return AjaxResult.success(resultMap);
    }

    @Override
    public AjaxResult syncVisitor(VisitorSyncRequest request) {

        if (StringUtils.isNull(request.getId())) {
            return AjaxResult.error("请传入id");
        }

        VisitorDevice visitorDevice = visitorDeviceService.getById(request.getId());
        if (StringUtils.isNull(visitorDevice)) {
            return AjaxResult.error("未找到对应信息");
        }

        AccessDevice accessDevice = accessDeviceService.selectAccessDeviceById(visitorDevice.getDeviceId());
        Visitor visitor = visitorService.selectVisitorById(visitorDevice.getVisitorId());

        VisitorDevice update = new VisitorDevice();
        update.setId(visitorDevice.getId());
        update.setStatus(DoorDeviceConstant.DeviceStatus.SEND);
        visitorDeviceService.updateById(update);

        deviceVisitorCommandService.downDevicesVisitors(Collections.singletonList(accessDevice), Collections.singletonList(visitor));

        return AjaxResult.success("已下发设备，待回复");
    }
}
